#include <iostream>
using namespace std;

#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>

#include <ctime>

#include <string>

// 全局锁  直接用宏来初始化
//pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

// 线程数据，包含线程名字，也就是黄牛名字，还有线程对应的互斥锁
class ThreadData
{
public:
    ThreadData(const string& name, pthread_mutex_t* pmtx)
        :_name(name),
         _pmtx(pmtx)
    {}

public:
    string _name;
    pthread_mutex_t* _pmtx;
};

// 黄牛人数
#define THREAD_NUM 5

// 陈奕迅演唱会的票数tickets
int tickets = 1000;

// 黄牛抢票执行的方法
void* getTicket(void* arg)
{
    ThreadData* ptd = (ThreadData*)arg;
    // 每个黄牛疯狂抢tickets
    while(1)
    {
        pthread_mutex_lock(ptd->_pmtx);
        if(tickets > 0)
        {
            usleep(rand() % 2000);
            
            tickets--;
         
            // 当对临界资源访问完后就解锁
            pthread_mutex_unlock(ptd->_pmtx);
            printf("%s抢到票了, 此时ticket num ::%d\n", ptd->_name.c_str(), tickets);
        }
        else
        {
            // 当对临界资源访问完后就解锁，这里是当tickets == 0的情况，也要解锁
            pthread_mutex_unlock(ptd->_pmtx);

            printf("%s没抢到票, 票抢空了\n", ptd->_name.c_str());
            break;
        }
     
        // 抢到或没抢到票都执行一下后续动作，这里直接用usleep替代
        usleep(rand() % 5000);
    }


    // 记得要释放掉线程数据，不然内存泄漏
    delete ptd;

    return nullptr;
}



int main()
{
    //timeval StartTime;
    //gettimeofday(&StartTime, nullptr);

    //time_t startTime = time(nullptr);

    // 局部锁
    pthread_mutex_t mtx;
    // 默认给空就行
    pthread_mutex_init(&mtx, nullptr);

    // 种一颗时间种子
    srand((unsigned int)time(nullptr) ^ getpid() ^ 0x24233342);
    // 假设此时有三个黄牛进行抢票
    pthread_t tid[THREAD_NUM];

    for(int i = 0; i < THREAD_NUM; ++i)
    {
        string tmp;
        tmp += to_string(i + 1) + "号黄牛";
        ThreadData* ptd = new ThreadData(tmp, &mtx);

        // 每个黄牛去抢票
        pthread_create(tid + i, nullptr, getTicket, (void*)ptd);
    }

    // 等待每个黄牛抢完票后退出
    for(int i = 0; i < THREAD_NUM; ++i)
    {
        pthread_join(tid[i], nullptr);
    }

    pthread_mutex_destroy(&mtx);
 
    //timeval EndTime;
    //gettimeofday(&StartTime, nullptr);

    //int s = EndTime.tv_sec + EndTime.tv_usec;
    //int e = StartTime.tv_sec + StartTime.tv_usec;
    //unsigned long res = (EndTime.tv_sec - StartTime.tv_sec) * 1000000 + EndTime.tv_usec - StartTime.tv_usec;
 
    //time_t endTime = time(nullptr);

    //printf("time is ::%lu\n", endTime - startTime);
    //printf("time is ::%lu\n", e - s);

    return 0;
}

//#include <iostream>
//using namespace std;
//
//#include <pthread.h>
//#include <unistd.h>
//#include <ctime>
//
//#include <string>
//
//// 线程数据，包含线程名字，也就是黄牛名字，还有线程对应的互斥锁
//class ThreadData
//{
//public:
//    ThreadData(const string& name, pthread_mutex_t* pmtx)
//        :_name(name),
//         _pmtx(pmtx)
//    {}
//
//public:
//    string _name;
//    pthread_mutex_t* _pmtx;
//};
//
//// 黄牛人数
//#define THREAD_NUM 5
//
//// 陈奕迅演唱会的票数tickets
//int tickets = 1000;
//
//// 黄牛抢票执行的方法
//void* getTicket(void* arg)
//{
//    ThreadData* ptd = (ThreadData*)arg;
//    // 每个黄牛疯狂抢tickets
//    while(1)
//    {
//        pthread_mutex_lock(ptd->_pmtx);
//        if(tickets > 0)
//        {
//            usleep(rand() % 2000);
//            tickets--;
//            printf("%s抢到票了, 此时ticket num ::%d\n", ptd->_name.c_str(), tickets);
//            
//            // 当对临界资源访问完后就解锁
//            pthread_mutex_unlock(ptd->_pmtx);
//        }
//        else
//        {
//            // 当对临界资源访问完后就解锁，这里是当tickets == 0的情况，也要解锁
//            pthread_mutex_unlock(ptd->_pmtx);
//
//            printf("%s没抢到票, 票抢空了\n", ptd->_name.c_str());
//        }
//        
//        // 抢到或没抢到票都执行一下后续动作，这里直接用usleep替代
//        usleep(rand() % 5000);
//    }
//
//
//    // 记得要释放掉线程数据，不然内存泄漏
//    delete ptd;
//
//    return nullptr;
//}
//
//int main()
//{
//    // 局部锁
//    pthread_mutex_t mtx;
//    // 默认给空就行
//    pthread_mutex_init(&mtx, nullptr);
//
//    // 种一颗随机数种子
//    srand((unsigned int)time(nullptr) ^ getpid() ^ 0x24233342);
//    // 假设此时有三个黄牛进行抢票
//    pthread_t tid[THREAD_NUM];
//
//    for(int i = 0; i < THREAD_NUM; ++i)
//    {
//        string tmp;
//        tmp += to_string(i + 1) + "号黄牛";
//        ThreadData* ptd = new ThreadData(tmp, &mtx);
//
//        // 每个黄牛去抢票
//        pthread_create(tid + i, nullptr, getTicket, (void*)ptd);
//    }
//
//	while(1)
//	{
//		if(tickets == 0)
//		{
//			cout << "票抢光了，准备补票中..." << endl;
//			sleep(rand() % 10);
//			tickets = 500;
//			break;
//		}
//		sleep(1);
//	}
//
//    // 等待每个黄牛抢完票后退出
//    for(int i = 0; i < THREAD_NUM; ++i)
//    {
//        pthread_join(tid[i], nullptr);
//    }
//
//    pthread_mutex_destroy(&mtx);
//    return 0;
//}
